package com.csthink.web.infrastructure.config;

import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;

import java.util.List;


/**
 * 访问: "<a href="http://ip:port/swagger-ui/index.html">...</a>"
 * http://<IP:PORT>/<context-path>/swagger-ui/index.html
 * http://<IP:PORT>/<context-path>/v3/api-docs?group={spring.application.name}
 *
 * @author <a href="mailto:security.2009@live.cn">Mars</a>
 * @since 2023-09-09
 */
@Configuration
@EnableOpenApi
@ConditionalOnClass(Docket.class)
public class SwaggerConfig extends WebMvcConfigurationSupport {

    @Value("${swagger.api.version:1.0}")
    private String apiVersion;

    @Value("${swagger.enabled:false}")
    private Boolean swaggerEnabled;

    @Value("${swagger.host:}")
    private String swaggerHost;

    @Setter(onMethod_ = @Autowired)
    private Environment environment;

    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/swagger-ui/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/")
                .resourceChain(false);
    }

    @Override
    protected void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/swagger-ui/")
                .setViewName("forward:/swagger-ui/index.html");
    }

    @Bean
    public Docket createRestApi() {
//        String swaggerHost = environment.getProperty("swagger.host");
//        Boolean swaggerEnabled = environment.getProperty("swagger.enabled", Boolean.class);
        String appName = environment.getProperty("spring.application.name");
        Docket docket = new Docket(DocumentationType.OAS_30);
        docket.enable(swaggerEnabled);

        docket.groupName(appName)
                .host(swaggerHost)
                .apiInfo(apiInfo())
//                .useDefaultResponseMessages(false)
//                .globalResponses(HttpMethod.GET, getCustomizedResponseMessages())
//                .globalResponses(HttpMethod.POST, getCustomizedResponseMessages())
//                .globalResponses(HttpMethod.PUT, getCustomizedResponseMessages())
//                .globalResponses(HttpMethod.DELETE, getCustomizedResponseMessages())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.csthink.web.interfaces"))
                .paths(PathSelectors.regex("/version.txt").negate())
                .paths(PathSelectors.regex("/.*"))
                .build()
//                .securitySchemes(List.of(apiKey()))
//                .securityContexts(Collections.singletonList(securityContext()));
                .securitySchemes(List.of(tokenScheme()))
                .securityContexts(List.of(tokenContext()));


        return docket;
    }

    private HttpAuthenticationScheme tokenScheme() {
        return HttpAuthenticationScheme.JWT_BEARER_BUILDER.name("Authorization").build();
    }

    private SecurityContext tokenContext() {
        return SecurityContext.builder()
                .securityReferences(List.of(SecurityReference.builder()
                        .scopes(new AuthorizationScope[0])
                        .reference("Authorization")
                        .build()))
                .operationSelector(o -> o.requestMappingPattern().matches("/.*"))
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("CSTHINK Web API Documentation")
                .contact(new Contact("Mars", "https://github.com/csthink", "security.2009@live.cn"))
                .description("Run login-controller to get the JWT token from response, " +
                        "click Authorize button on the right side, input value 'Bearer Jwt token' and then click Authorize button.")
                .version(apiVersion)
                .build();
    }

    /*private ApiKey apiKey() {
        return new ApiKey("apiKey", "Authorization", "header");
    }

    private SecurityContext securityContext() {
        return SecurityContext.builder()
                .securityReferences(defaultAuth())
                .forPaths(PathSelectors.any())
                .build();
    }

    private List<SecurityReference> defaultAuth() {
        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        return List.of(new SecurityReference("apiKey", authorizationScopes));
    }*/

    /*private List<Response> getCustomizedResponseMessages() {
        return newArrayList(
                new ResponseBuilder().code("500")
                        .description("500 message").build(),
                new ResponseBuilder().code("403")
                        .description("Forbidden!!!!!").build()
        );
    }*/

}
